CloudFrontのオリジンに別アカウントのALBとS3を指定する
こんにちは、なおにしです。
CloudFrontのオリジンに別アカウントのALBとS3を設定してみたのでご紹介します。
はじめに
CloudFront を利用した場合、料金表のページにも明記されているとおりオリジン→CloudFrontのデータ転送料金は発生しません。
コンテンツのオリジンとして AWS のサービスを使用している場合、オリジンからエッジロケーションへのデータ転送 (Amazon CloudFront のオリジンフェッチ) は無料です。これは、すべての AWS リージョンからすべてのグローバル CloudFront エッジロケーションへのデータ転送に適用されます。
一方、CloudFront→オリジンのデータ転送料金は発生します。また、ALBでのLCU(ロードバランサーキャパシティーユニット)やS3バケットのリクエスト料金など、データ転送自体ではなく、テータ転送が行われる際に生じる料金についてはCloudFrontの使用有無に関わらず発生します。
とはいえ、キャッシュを有効活用することができればCloudFrontからオリジンに対するアクセスが抑えられるため、例えばオリジンでECサイトをホストしていて商品画像のようなデータのやり取りが多い場合は、CloudFrontからのデータ転送(OUT)料金が大きくなるかと思います。
CloudFrontにおけるデータ転送(OUT)料金はデータ転送量に応じた従量課金で、転送量が多くなると割引されるようになっています。しかし、料金表のとおりテータ転送量に応じた割引が適用されるためには少なくとも10TB/月を超えるデータ転送量が必要となり、ある程度大規模な環境でないと難しいのではないでしょうか。
そういった時にCloudFront のコスト削減を検討するのであれば、以下の対応などが候補として挙がるかと思います。
- CloudFrontを1つのAWSアカウントに集約 ※ 所有している複数のAWSアカウントにCloudFront を設置している場合
- 割引プランの適用
CloudFront を1つのAWSアカウントに集約
CloudFrontのデータ転送量に対する割引の適用はディストリビューションごとではなく、AWSアカウントごとに基準のデータ転送量を超えているかどうかです。
したがって、例えばCloudFront を複数のAWSアカウントで運用している場合、それぞれのアカウントにおけるCloudFront ディストリビューションではデータ転送量が10TB/月を超えなくても、1つのアカウントに集約することで10TB/月を超えるのであれば適用対象となり得ます。
もちろん、CloudFrontを別アカウントに切り出すことによって、IaCを用いた環境構築や請求額の管理などが煩雑になるというデメリットも発生しますので、実際に集約するかどうかはメリット/デメリットを比較して検討することが重要かと思います。
割引プランの適用
データ転送量に応じた割引だけではなく、CloudFrontでは「CloudFront Security Savings Bundle」という割引プランも準備されています。
内容としてはEC2でSavings Plans(SP)を購入する場合と似ています。一定期間の使用を一定料金でコミットすることで割引を受けることができます。
AWSマネジメントコンソールで [CloudFront > Savings Bundle > 購入] と進むと「使用量計算ツール」も準備されていますので、こちらの画面を見ていただく方がイメージしやすいかと思います。例えば日本でのデータ転送量が「3TB/月」で発生していると仮定して試算するのであれば、以下のようになります。
プラン名に「Security」とあるとおり、割引対象にAWS WAFの利用料金も含まれています。AWS WAF の料金想定は実際に適用されているWebACLのルール数などで違ってくるかと思いますが、少なくとも上記の場合であれば「$26.05」がAWS WAF の利用料金から割引されます。ただし、以下にご注意ください。
AWS Marketplace を通じてサブスクライブされたマネージド WAF ルールは、CloudFront Security Savings Bundle の対象外です。
上記の例でコミットする場合は以下のように料金を入力します。
その他の詳細については以下のCloudFront Security Savings Bundle に関する「よくある質問」ページもご参照ください。
CloudFront Security Savings Bundle では一定金額をコミットするので、ある一定以上のベースラインとなり得るデータ転送料金に対して購入しないと、データ転送量が想定外に発生しなかった際には逆にコスト増になる可能性があります。
ベースラインを大きくしてCloudFront Security Savings Bundle の恩恵をより大きくするためにも、CloudFront を1つのAWSアカウントに集約するメリットはあるかと思います。というわけで、実際に集約するわけではありませんが、CloudFrontのオリジンに別アカウントのALBとS3 バケットを指定することができることを確認してみます。
CloudFront Security Savings Bundle はコスト削減につながるメリットの大きな料金プランですが、もし弊社サービスと併せてご検討いただいている方は以下にご注意ください。
「EC2・CDN割引プラン」におけるCloudFrontのアウトバウンド通信費には「CloudFront Security Savings Bundle」よりも大きな割引率が適用されますので、もし興味ありましたらご検討いただけると幸いです。
やってみた
以下のようにCloudFrontのオリジンとして、EC2インスタンスをバックエンドにしたALBと、静的コンテンツを格納したS3バケットをそれぞれ指定する構成を考えてみます。
EC2 インスタンス、ALB、S3バケットの作成については詳細を割愛します。注意点としては、今回はRoute 53の設定をCloudFrontを集約するアカウントに寄せているため、ALBに適用するACM発行の証明書に関しても、DNS検証の際のCNAMEをこちらのRoute 53に設定しました。詳細は以下の記事をご参照ください。
また、S3バケットは作成時点では以下の設定が適用されているものとします。
- Amazon S3 マネージドキーを使用したサーバー側の暗号化 (SSE-S3)
- ACL無効
- パブリックアクセスをすべて ブロック
- バケットポリシー無し
Route 53 の設定(ALB用のレコード作成)
今回はCloudFront を設置する方のアカウントでレコードを登録しました。別アカウントに存在するALBでもエイリアスレコードとして登録することができます。
CloudFront ディストリビューションの作成
続いてCloudFront ディストリビューションを作成します。(かなり縦長いですが各種設定項目の文字起こしを割愛するためにスクリーンショットをそのまま転記します)
特記事項としては、代替ドメイン名 (CNAME) には後ほど設定するCloudFront用のドメイン名を「other-account.example.com」として事前に設定しておきます。また、ACMによる証明書も事前に発行済みのものを使用します。
以下の設定で作成されたCloudFront ディストリビューションはオリジンとしてALBを指定しただけの状態になります。
Route 53 の設定(CloudFront用のレコード作成)
CloudFront ディストリビューションが作成されたら、それを指すエイリアスレコードをRoute 53で作成します。今回は同一アカウント内に存在するリソースであるため、対象のCloudFront ディストリビューションがサジェストされます。
CloudFront のオリジンとしてS3を追加(OAC設定)
別アカウントのS3バケットをCloudFront のオリジンとして参照する場合、OACの設定がアカウント跨ぎになります。
以下の記事で同様の操作を検証していますが、OAIだった時の内容であるため改めてOACのパターンとして検証してみます。
まずオリジンを作成します。以下のように作成画面を開いた段階ではOAC設定は見当たりませんが、Origin domain に事前に作成しておいたS3バケットのドメインを入力すると選択肢が表示されます。なお、設定してすぐにアクセス確認をする場合は、S3バケットのドメイン名の指定時に以下記事の内容もご留意ください。
オリジンアクセスコントロールの設定を作成します。
作成すると以下のようにS3 バケットに適用するバケットポリシーをコピーできるようになるので、ポリシーをコピーします。
コピーされた内容は以下のとおりです。
{
"Version": "2008-10-17",
"Id": "PolicyForCloudFrontPrivateContent",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::(AWSアカウントID):distribution/(CloudFrontディストリビューションID)"
}
}
}
]
}
上記をS3バケットに適用します。そのまま貼り付けると「"Resource": "arn:aws:s3:::/*"」の部分でエラーが発生しますので、実際には以下のように対象バケットを指定する必要があります。
バケットポリシーの設定が終わったらオリジンの作成を完了します。
CloudFront のビヘイビア(パスパターン)の設定
特定のパスに対するアクセスを上記で作成したS3 オリジンに向けるためにビヘイビアを設定します。今回は「/images/*」というパスパターンにアクセスが来たらS3 オリジンに接続されるようにします。
コンテンツの格納と動作確認
パスパターンを「/images/*」としたため、S3 バケット内も同様の構成として、テスト用の画像ファイルをアップロードします。
EC2にはWebサーバソフトウェアをインストールの上、ドキュメントルート直下のindex.htmlに以下のシンプルな内容を記述します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>CloudFrontのオリジンに別アカウントのALBとS3を指定する</title>
</head>
<body>
<h1>CloudFrontのオリジンに別アカウントのALBとS3を指定する</h1>
<h2>S3バケットに格納された画像</h2>
<img src="https://other-account.example.com/images/sample-image.png" alt="サンプル画像">
</body>
</html>
実際に「https://other-account.example.com/ 」にアクセスした結果は以下のとおりです。
まとめ
今回はCloudFrontのオリジンとして使用したS3バケットの暗号化タイプがSSE-S3だったため、OACの設定でもスムーズに連携することができました。もしOACのメリットであるSSE-KMSを利用したS3バケットとの連携であればもう少し工夫が必要になるかと思います。詳細は以下の記事もご参照ください。
本記事がどなたかのお役に立てれば幸いです。